home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-06-28 | 24.7 KB | 470 lines | [TEXT/pdos] |
- Rez 102
- by: Tim Swihart
-
-
- This time around, we'll look at Part 2 of the resource tutorial, naming
- conventions, and places to go for more detailed information. This one
- should be fairly short since the differences between Part 1 and Part 2 of
- the tutorial are minor and we've already laid a pretty solid ground work
- for the basics of resources.
-
- For those of you who are still wondering why the changes from one part of
- the resource tutorial to the next seem to be pretty small, it's on purpose.
- This allows you to see the minimum amount of code needed to move from
- one phase to the next. It allows you to figure out which parts of the
- code are needed to start the tools, which parts are needed to open a
- window, which parts are needed to insert a menu bar, etc. By breaking the
- application into smaller pieces, it's a lot easier to digest. Many of you
- may want to just grab the complete app and figure it out for yourself,
- others would prefer to do it in increments so that they don't waste time
- trying to decipher some one else's thought process. :-)
-
- The rest of this file assumes that you've already read (and more or less
- understood) "Rez 101" which I uploaded earlier. If you're still lost and
- this file only makes it worse, then either send email or post a plea for
- help. If I don't know you're lost, I can't help (and neither can any of
- the other developers/programmers/hackers/etc that can help).
-
-
- What's New in Part 2?
-
- Part 1 showed you how to start up the tools using a single tool call
- (StartUpTools) instead of a series of routines (like we used to have to
- do before System Disk 5.0 saved us from the drudgery). In Part 1, the
- application started the tools, beeped three times, and shutdown the tools,
- returning you to wherever you launched the app from. This time around,
- we'll do all of that, but AFTER the tools are started and BEFORE the three
- calls to SysBeep, we'll insert the application's menu bar.
-
- We'll still shutdown afterwards, so you'll never get a chance to do
- anything else in this version of the application. Part 2.5 adds an Event
- Loop to the application so that we can play with Desk Accessories, pick
- menu items, etc.
-
-
- What's on the Menu (Bar)?
-
- Prior to System Disk 5.0, menus were inserted one at a time in a loop. If
- your menu bar had ten menus, you had to make the tool call "InsertMenu"
- ten times. Not all that hard, but it could be easier. Menus also had to be
- described in a weird text format (clearly documented in several outstanding
- books on e subject such as the Addison-Wesley "Programmer's Introduction
- to the Apple IIGS" and the Apple IIGS Toolbox Reference Volume 1).
-
- Wouldn't it be nice if you could just type in your menus, using a tools that
- made it look and feel like you were editing REAL menus, not just a bunch of
- text laying around? GeneSys (from Simple Software Systems International)
- and several other tools (AppMaker/GS, DesignMaster, etc) allow you to
- create your menus in a format that looks like you're really editing an actual
- menu! Sure does make it a lot easier to see what your menus will look like
- (and to tweak them before they're really part of your application).
-
- But what if you suddenly wanted to have your menus in French? Or you
- wanted the text to be in Pig Latin? Using the "old way" of doing things,
- you'd have to edit your application's source, recompile, re-link, and run
- your application to see the end result (hmmm, maybe they looked better in
- English after all). Using power tools like GeneSys, and taking full
- advantage of resources, your menus are NOT part of your application source
- code - they're resources (which are discrete units of data, right?
- [say, "right!"]). That means you can simply edit the text in your menu
- resources and re-run your application! No compiling, no linking, no
- waiting, and the editor looks like a menu editor should instead of just
- another text editor.
-
-
- Look at the Shiny New Line:
-
- If you compare the last chunk of source code (the routine named "main) in
- the rTutor.CC file from Part 2 to the same chunk from Part 2, you'll notice
- that I added ONE line of code to it. That line of code simply calls the
- procedure that inserts the menu bar and all of its menus for us. By "hiding"
- the code to actually insert the menu bar in another area of the source code,
- I was able to make the "main" routine far more readable. Look at the handful
- of lines of source that are in Part 2 and you can immediately tell what's
- going on. Imagine if you expanded each routine right there instead of using
- separate routines - it would be MUCH less obvious what was going on!
-
- Readability is a BIG concern - especially when you're publishing your source
- for the world to learn from. If they can't read it, they can't learn very
- well.
-
-
- Naming Conventions are Your Friends!:
-
- Despite what some folks say, it's important that you follow some sort of
- naming conventions in your source code so that it's easier to read. You may
- know NOW what all of it does, but in a few weeks or months when you come
- back to fix a bug, you'll have forgotten parts of it. It's also very
- important to have easily readable code if it's going to be published (in an
- article for example), turned in for a grade (do you really want the
- instructor to have to guess what you're doing?), or used by others (who may
- have to fix your bugs).
-
- In the source code I write, I follow several conventions to make things
- easier. The first one is to start all global variables with a lower case
- "g" (for "global"). This lets me quickly tell if I'm assigning an important
- value to a local variable (where it can quickly get lost) or to a global
- variable (where it will live forever). I also capitalize the "words" within
- a global variables name (i.e.: gToolListRef) - notice how the words are run
- together in my global variables? Local variables have their "words"
- separated with an underscore (i.e.: my_mbar_hndl) and are all lower case.
- That gives me three different ways to tell at a glance whether a variable
- is global or local. You may want to use only one or two ways instead of all
- three - do what ever works for you, just be consistent.
-
- All constants within my source start with a lower case "k" (for "konstant").
- why not a lower case "c"? Because I picked this up from somebody else and
- they used a "k" (not all conventions make a lot of sense, but they are
- conventions...) :-) Constants, like globals variables, have their "words"
- run together with each "word" starting with an upper case letter (i.e:
- "kShowClipItem").
-
- Anywhere in my source that I'd normally imbed a hard-coded number (such
- as passing a menu ID to FixAppleMenu), I use a constant. All of my
- constants are defined at the top of the file so that I can easily find them.
- They all have a comment after them to job my memory about what they're
- for. I also tend to group them logically - all menu ID constants in one
- group, all menu items ID's for the first menu in the next group, all menus
- item ID's for the second menu in the next group, etc. I also tend to
- separate major sections of constants from one another with a dividing
- line (in a comment). This lets me group all of the smaller groups of
- menu-related constants into one area, window-related constants into
- another, etc. All of these larger groups of constant come one behind
- the other in near the top of the file.
-
- I generally add new constants to the end of the constants area so that I can
- tell faster what's different from one version of a source file to the next.
- (the new stuff will be at the bottom of the constants section).
-
- I generally start my procedures off with the characters "do_" - it makes the
- source where I call those routines more readable (i.e.: "do_make_menus" is
- more readable than "menus" or even "make_menus"). Like local variables, I
- name my procedures with all lower case letters and separate the "words"
- within their names by underscores.
-
- Each routine in the source file is separated from the preceding one by a
- dividing line (in a comment) to make it more obvious where one routine
- starts and another ends.
-
- If you see a variable that STARTS with an underscore, then it's a "system"
- variable - i.e.: it's defined for us by the language author. In the
- rTutor.cc file, you can find a couple such variables ("_ownerid" and
- "_toolerr"). Both of these are defined by Start.Root and are given values
- by either Start.Root (in the case of "_ownerID" which is simply the app's
- Memory Manager user ID) or the library (in the case of "_toolerr" which is
- used after all tool calls to save whatever error the call returned).
-
- DO NOT NAME ANY OF YOUR OWN VARIABLES WITH A LEADING UNDERSCORE!!!
-
- You'll confuse yourself into thinking they're "system" variables and you'll
- confuse others who have to read your source! :-)
-
- While we're on the subject, take full advantage of the pre-defined constants
- that are in the interface files. Things like using "refIsResource" instead
- of "2" makes a LOT of difference when you're trying to see if the parameters
- to a call are right. One is intuitive ("refIsResource") and one is asking
- for trouble (what's "2" for anyways?). The Toolbox Reference Manuals have
- a summary of all constants related to a particular tool Manager at the end
- of each chapter. Each of those constants SHOULD be in the interfaces (if
- they're not, report it to Apple via the interfaces bug report form in the
- Release Notes for "APW Tools & Interfaces").
-
-
- Now How Do We Do Menus?
-
- Using System Disk 5.0 and up, we can insert an ENTIRE menu bar, with a
- virtually unlimited number of menus (they really should fit on the screen,
- but that's about the only limit) can be inserted with ONE tool call! Since
- we're only interested in using resources, I won't describe how this call
- could be used with hard-coded menu descriptions (after all, this is the
- 90's, the old way is passe'). :-)
-
- Once we have our menu bar resource created (using a desktop tool like
- GeneSys or the resource compiler [Rez] from APDA), we can insert it into the
- running application by calling NewMenuBar2 (remember the "2" on the end,
- leave it off and you're making a VERY different tool call!). NewMenuBar2
- requires three parameters as input and returns a handle to the newly
- created menu bar. The three parameters are:
-
- 1) A reference descriptor (which I defined in Rez 101) to tell whether we're
- using a resource, handle, or pointer to reference the menu bar. Naturally,
- we're using a resource, so we use the Apple-provided constant
- "refIsResource" (this lets us not worry about what the actual value is that
- goes here - it also makes the code a LOT more readable). This parameter is
- a "word" in size (i.e.: it takes up two bytes on the stack).
-
- 2) The reference to the menu bar. Parameter #1 described the reference
- and Parameter #2 is the reference - be sure you understand the difference
- (one of them describes something and the other IS something). Since we're
- using resources, this reference is simply the resource ID of the menu bar
- resource. There is a standard type defined for menu bar resources and you
- HAVE to use it or this call won't be able to find your menu bar in the
- resource fork. Remember, ALL resources are identified by the combination
- of BOTH their type and their ID. This parameter is a "long" in size (i.e.:
- it takes up four bytes on the stack). Pay attention here! It's easy to
- accidentally pass only a word (especially if you're using C [we are] and
- don't have prototyped interfaces [we don't because APW C doesn't support
- them]). If you only pass a word for this parameter, the tool call will
- still pull a LONG off the stack and all sorts of weird things can start
- happening.
-
- 3) A pointer to the PORT of the window that you want the menu bar inserted
- into. Huh? We don't want our main menu in a window! We want it at the
- top of the screen!!!! Relax, if you pass a NIL (four bytes that are zero),
- then NewMenuBar2 will insert the new menu bar in the "system menu bar"
- (better known as the top of the screen) <grin>. Since you pass four bytes
- of zeros for a NIL, this parameter must be a "long" in size (it is). If you
- do try to put a menu bar in a window, be sure you pass a pointer to the
- window's PORT - if you don't know what a graf port pointer is, then look it
- up in Toolbox Reference Volume 2 (and don't try to stick a menu bar in a
- window if you don't understand ports). :-)
-
-
- What Else?
-
- Actually, NewMenuBar2 will only read in your menu bar resource (and all
- associated menus and menu items) and insert it. You have to make a couple
- of other calls to tell the Menu Manager that this newly inserted menu is the
- "system" menu and to draw it on the screen. (If you don't draw it, the user
- can't see it). :-)
-
- First, we call "SetSysBar" and pass it the handle that we got back from
- NewMenuBar2. SetSysBar tells the Menu Manager that the menu handle you
- just gave it is supposed to be treated as the system menu. SetSysBar
- doesn't return anything.
-
- Next, we call "SetMenuBar" and pass it a NIL. This tells the Menu Manager
- which menu bar is the "current" one. Confused about system menus and
- current menus? Don't be - just think of what it takes for the Menu Manager
- to keep track of the situation where you have a menu bar at the top of the
- screen (the "system" menu bar) and a desk accessory (such as C. K. Haun's
- "WriteIt!" NDA) that also have a menu bar in their window. How does the
- Menu Manager figure out whether the application or the desk accessory
- should be told that a menu item was picked? That's where "current" and
- "system" menu bar meanings come into play. If you're still confused, don't
- worry about it. Just make both of these calls and don't stick any menu bars
- in windows, then you won't have to hassle with it. :-)
-
- So, we've inserted the menu bar, told the Menu Manager to make it the
- "system" menu bar, and told the Menu Manager to also make it the "current"
- menu bar. Now do we draw it so the user can see it?
-
- NO! What kind of application would you have if it didn't support desk
- accessories???!!! Oh yeah, NDA's... Forgot about them, didn't you
- (and only two paragraphs after I mentioned an NDA by name). There are a few
- applications out there that don't bother to support NDA's and that's an
- incredible shame because it only takes ONE tool call to insert NDA's into
- your Apple menu! Sure, you have to have certain tool sets started up first,
- but so what! Odds are you'd have those tool sets started anyways, so all
- we're REALLY talking about IS just ONE tool call!
-
- That "magic" tool call is "FixAppleMenu" and you pass it the menu ID of your
- Apple menu. Actually, you can insert NDA's on ANY menu (as my Two
- Apples NDA showed years ago), but tradition (and the STRONG desire to have
- an intuitive user interface) dictates that we only insert NDA's into the
- "Apple" menu.
-
- Does that mean we should just pass a "1" for the menu ID used in this call?
- NO!!!! There is NOTHING requiring the Apple menu to have an ID of 1! In
- fact, many very well known applications do NOT use "1" for the ID of the
- Apple menu (I know, I made that rather bogus assumption in an early
- version of Two Apples NDA <blush> and had to fix it later). When you
- created your menu bar, you had to give each menu in it a unique ID. That's
- the ID you pass to FixAppleMenu.
-
- One more thing... Did you ever notice that menus are all different widths
- and lengths? That they always seem to just "exactly" fit around the text of
- the items within them? Notice that when you created your menus, you
- didn't do ANYTHING to indicate how wide or how long the menus should be?
- Then how come the menus are all the right size?
-
- Simple, you make a tool call and that tool measures all the text in each menu
- and makes the menus long enough and wide enough to hold the contents of
- each menu. The tool call I'm referring to is "FixMenuBar" and it requires no
- input parameters. It does however return a "word" that tells you how tall
- the menu is. The Rez tutorial application puts the returned menu height in a
- local variable (so it's lost as soon as the "do_make_menus" routine is
- finished). We never really use this number in the things we're doing, so
- that's why I didn't bother to keep it around.
-
-
- Now Can I Draw the Menu Bar?
-
- Yes, now that we've inserted the menu bar, told the Menu Manager that it
- was both the "system" and the "current" menu bar, added NDA's to our Apple
- menu, and made sure the heights and widths of the menus were all correct,
- we can finally draw the menu bar! You do this with.... (you guessed it)
- "DrawMenuBar". This call takes no parameters as input and returns nothing
- (kind of like SysBeep, only more special purpose in nature).
-
-
- Menu Bars and Rez:
-
- Notice I mentioned using a desktop tool like GeneSys to lay out your menus?
- Notice that the tutorial source uses Rez? Confused over which tool to use?
- Don't be!!! GeneSys is more intuitive than Rez for laying out menus if you
- don't really understand what you're doing. But, since I uploaded Rez source
- for the menu bars, I'd better explain it here.
-
- Before we jump into all the various types of resource needed to make a
- menu bar work, let's first look at what's in a menu bar from the
- application/user perspective. The menu bar contains several menus (i.e.:
- it's a list of menus). The menus each contain several menu items (i.e.:
- they're lists of items). Each menu has a name and each item has a name.
- Menus and menu items also have some special attributes (whether or not
- they're disabled, whether or not the items have a command key equivalent,
- etc).
-
- In English, this means we need to have two types of lists (one type is a
- list of menus and the other is a list of menu items), text strings for
- each menu and each item, and attributes for menus and items. Remembering
- from Rez 101 that each type of resource is different and that Apple defined
- a bunch of "standard" resource types already, we can guess that we should
- have the following types of resources:
-
- - rMenuBar (where we list the menus in the menu bar)
- - rMenu (where we list the menu items and attributes for each menu)
- - rMenuItem (where we describe each menu item)
- - rPString (where we list the "text" for each menu or item)
-
- (rPString means that we're using a resource [that's what the "r" is for]
- and it's a Pascal-style string [that's what the "P" is for] - because
- that's what the Menu Manager wants).
-
- There are a couple of ways to lay out the Rez source for a complete set of
- menu bar/menus/menu items. My preference is to lay out the menu bar
- itself (which is a simple list of the resource ID's of the menus in the menu
- bar), then the first menu, then each item in that menu. After the menu, but
- BEFORE the first item is described, I list the rPString for the name of that
- menu (just to keep it close to the menu definition). After each item, but
- BEFORE the next item, I list the "rPString" for that item (again, just to
- keep it close to the menu item's definition).
-
- The alternate way is to list the menu bar, then the menus, then the menu
- items, then all of the rPStrings. I don't like this one because it pushes
- the rPStrings too far away from the menus they're with and I like keeping
- things close together (to avoid unnecessary scrolling). Which method you
- use is up to you (you could even come up with your own).
-
- I also define constants for ALL resource ID's used by the menu bar, menus,
- menu items, and rPStrings! Why? Because it's a LOT easier to figure out
- that "resource rMenu (kAppleMID)" and "resource rPString (kAppleMID)" go
- together than it would be if "kAppleMID" were just a number. It also helps
- you figure out later which item is which number (gee, I want to insert an
- item in the File menu right after "Save", but I'm not sure which one of
- these menus is the File menu and which menu item is "Save" and....).
- Remember, naming conventions are your friends!
-
- Inside the Rez source file (rTutor.rez), near the beginning of the menu
- layout section, are several lines of comments that spell out the strategy
- for laying out menu bars, menus, and menu items in Rez using the strategy
- I prefer. Read those six steps if you're still a little fuzzy about how to
- do all of this. It looks like a lot of typing, but most of us just use
- cut and paste instead of typing new menus, menu items, etc. Just be
- careful to edit ALL of the fields of the pasted menu item or you'll get
- some bizarre results... :-)
-
- In your C (or Asm or Pascal) source file, the constants for menu bars
- should be long's (i.e.: four bytes) - that's why they have an "L" after
- them. You'll be making toolbox calls using the resource ID's as references
- to your menu bar (such as NewMenuBar2). The constants for menus and menu
- items should be WORDS (not longs, despite the fact that I accidently left
- "L" on the end of each of them in Part 2's C source <blush>). Why?
- Because you'll be passing these numbers to tool calls such as FixAppleMenu
- that expect a word. We'll cover this in more detail in Part 2.5 once we've
- put in the event loop. If you're in doubt about whether to use a word or
- a long, look at the toolbox reference manual's description of the call
- you're going to make and pass what it expects. The only languages that
- will check the sizes for you are Pascal and an ANSI C (but only if the
- interfaces that you use are "prototyped"). If you use smart enough
- assembler macros, it should be able to check for you also.
-
-
- Review Time:
-
- OK, what did it take to go from Part 1 (start the tools, beep three times,
- shut down) to Part 2 (start the tools, insert a menu bar, beep three times,
- shut down)? We had to add one line of source to "main" (right before the
- beeps) and we had to write the routine that we wanted to call from "main"
- (I'm referring of course to the routine named "do_make_menus"). We could
- have slipped the call to "do_make_menus" into the middle of the SysBeeps
- or at the end. I didn't just put them at the beginning for the heck of it.
- Later, we'll replace the SysBeeps with real stuff that HAS to come AFTER
- the menu bar is inserted, so the SysBeeps sort of mark our place for us.
-
-
- Need More Info?
-
- You can get a different explanation of how Part 2 works by reading the
- comments in the rTutor.cc source code. Be sure to read them in the order
- the program runs AFTER it's compiled - i.e.: read the comments in "main",
- jump to the comments in "do_init_rom" when you hit that line, come back to
- "main" after "do_init_rom" is done, go to the comments in "do_make_menus",
- etc. That way, you'll read the comments in the same order the program is
- actually running - it should help...
-
- You can also consult the following references for more information:
-
- - Apple IIGS Toolbox Reference, Volume 1 (for details on SetSysBar,
- SetMenuBar, FixAppleMenu, FixMenuBar, and DrawMenuBar).
-
- - Apple IIGS Toolbox Reference, Volume 3 (for details on NewMenuBar2 and
- menu bar resources).
-
-
- OK, So I Lied:
-
- I told you at the beginning that this would be a short file compared to Rez
- 101. I just counted the number of words in this one and in Rez 101
- (actually, my word processor counted the words, I'm lazy <grin>) and here's
- how Rez 102 stacks up against Rez 101 size-wise:
-
- Version Num. Words Num. Characters
- -------------------------------------------------
- Rez 101 4672 26698
- Rez 102 4483 24951
-
-
- Enjoy,
- Tim S.
-
- P.S.: Get Rez from APDA or Developer Tools Express if you don't have it yet
- or if you have the old version that was in "Programming Tools & Interfaces
- for APW v.1.1". Rez is part of the new "APW Tools & Interfaces v.1.1"
- package. New customers should order part number "A0240LL/A" (price $50,
- includes manual) and those of you who bought "Programming Tools &
- Interfaces for APW" should order the "update" version by requesting part
- number "A0241LL/A" (price $25, no new manual). These packages include
- three disks (one of which contains revised interfaces for APW/ORCA Asm
- and APW C). The other two disks contain:
-
- Rez (resource compiler)
- DeRez (resource decompiler)
-
- LinkIIGS (scriptable linker, creates OMF 2.0/2.1, auto-express's)
- Compact (converts OMF 1.0 to OMF 2.0 so files are smaller and faster)
-
- CrunchIIGS (converts ORCA/Pascal and ORCA/C compiled files for LinkIIGS)
- DiskCheck (checks for block conflicts, bad bitmaps, etc)
-
- DumpObj (lets you inspect/disassemble OMF files)
- Duplicate (copies files without losing resource forks)
-
- Equal (compares files byte by byte- can compare resource forks too)
- Express (convert older apps to take advantage of ExpressLoad in System 5.x)
-
- Files (super fancy catalog utility)
- Join (merge two files together - used by CrunchIIGS)
-
- MakeBin (convert linked apps to binary image for 8-bit stuff, etc)
- MakeDirect (create custom sized stack segments for your apps)
-
- MakeLib (library management tool)
- ResEqual (compares two resource forks, resource by resource)
-
- Search (finds text in files)
- Canon (makes sure you use proper casing for tool calls)
- Canon.dict (dictionary for Canon - supports 5.0.2 tool calls)
-
- (nice list, eh?) GET 'EM! ;-)
-